package cate.game.server.configuration;

import cate.game.GameBody;
import cate.game.common.rpc.RpcListener4Game;
import cate.game.common.rpc.RpcSender4Game;
import cate.game.db.GameMongoDao;
import cate.game.db.MongoCache;
import cate.game.db.mongo.cfg.AutoDeleteConfig;
import cate.game.db.sqlite.GameSqlite;
import cate.game.framework.GameFacilities;
import cate.game.server.GameServerApplication;
import cate.game.server.configuration.dao.MgDaoSetup;
import cate.game.server.configuration.part.MgCliPool;
import com.mongodb.client.MongoDatabase;
import cp.bi.CpBiClient;
import cp.game.framework.ApiCaller;
import cp.solution.define.HardRule;
import cp.solution.define.SrvType;
import easy.mongo.core.MgCli;
import easy.mongo.util.IndexUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.util.Collections;

@Slf4j
public class GameFacilitiesImpl implements GameFacilities {
    private GameBody game;

    public GameFacilitiesImpl(GameBody game) {
        this.game = game;
    }

    @Getter @Setter
    private ApiCaller api;

    @Getter @Setter
    private RpcSender4Game rpcSender;

    @Getter @Setter
    private RpcListener4Game rpcListener;

    @Getter @Setter
    private CpBiClient bi;

    @Getter @Setter
    private GameSqlite sqlite;

    private GameMongoDao mongoDao;

    @Override
    public synchronized GameMongoDao getMongo() {
        if(mongoDao == null) {
            mongoDao = new GameMongoDao();
            log.info("============== 准备mongoDao.setup ==============");
            mongoDao.setup(this.game);
            log.info("============== 完成mongoDao.setup ============== {}", GameMongoDao.ENABLE_NEW_TEMPLATE);
            if(GameMongoDao.ENABLE_NEW_TEMPLATE) {
                log.info("============== 进入MgDaoSetup(新模板已启用) ==============");
                MgCli mc = MgCliPool.instance.get(this.game.config.mongo);
                String gameDbName = getMongoDatabaseName(this.game.config.srvId);
                MongoDatabase database = mc.getDatabase(gameDbName);
                MgDaoSetup mdSetup = new MgDaoSetup(database, mongoDao);
                mdSetup.exe();
            }
        }
        return mongoDao;
    }

    private MongoTemplate mongoTemplate;
    @Override
    public MongoTemplate getMongoTemplate() {
        if(mongoTemplate == null) {
            final long beginTime = System.currentTimeMillis();
            MgCli mc = MgCliPool.instance.get(this.game.config.mongo);

            String gameDbName = getMongoDatabaseName(this.game.config.srvId);
            SimpleMongoClientDatabaseFactory factory = new SimpleMongoClientDatabaseFactory(mc.get(), gameDbName);
            //MongoDatabaseFactory factory = new SimpleMongoClientDatabaseFactory(mc.get(), cnf.getDatabase());

            MappingMongoConverter mongoConverter = getDefaultMongoConverter(factory);
            MyMongoTypeMapper mmtm = new MyMongoTypeMapper();
            //log.info("GameServerApplication.ctx.getClassLoader() = {}", GameServerApplication.ctx.getClassLoader());
            mmtm.setBeanClassLoader(GameServerApplication.ctx.getClassLoader());
            mongoConverter.setTypeMapper(mmtm);
            mongoTemplate = new MongoTemplate(factory, mongoConverter);

//            mongoTemplate = new MongoTemplate(factory);
            mongoTemplate.setApplicationContext(GameServerApplication.ctx);// new added

            for (AutoDeleteConfig cfg : AutoDeleteConfig.find(SrvType.game)) {
                IndexUtils.setExpire(mongoTemplate.getCollection(cfg.collection), cfg.field, cfg.expireAfter, cfg.timeUnit);
            }

            log.info("getMongoTemplate()初始化耗时:{}ms", (System.currentTimeMillis() - beginTime));
        }
        return mongoTemplate;
    }

    private static MappingMongoConverter getDefaultMongoConverter(MongoDatabaseFactory factory) {

        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MongoCustomConversions conversions = new MongoCustomConversions(Collections.emptyList());

        MongoMappingContext mappingContext = new MongoMappingContext();
        mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
        mappingContext.afterPropertiesSet();

        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
        converter.setCustomConversions(conversions);
        converter.setCodecRegistryProvider(factory);
        converter.afterPropertiesSet();

        return converter;
    }

    private MongoCache mongoCache = new MongoCache();
    @Override
    public MongoCache getMongoCache() {
        return mongoCache;
    }

    private String getMongoDatabaseName(int srvId) {
        return HardRule.getMongoDatabaseName(srvId);
    }

    @Override
    public void afterGameInitialize() {

    }
}
